package com.sloth.bear.controller;

import com.sloth.bear.annotation.NoAuth;
import com.sloth.bear.dto.entity.FileIndex;
import com.sloth.bear.service.FileIndexService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.catalina.connector.ClientAbortException;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * 文件流服务控制器 - 专门处理文件下载和流媒体
 */
@Slf4j
@RestController
@RequestMapping("/stream")
@RequiredArgsConstructor
public class FileStreamController {
    
    private final FileIndexService fileIndexService;
    
    /**
     * 流式传输视频文件
     */
    @NoAuth
    @GetMapping("/video/{fileId}")
    public void streamVideo(@PathVariable String fileId, 
                           @RequestHeader(value = "Range", required = false) String range,
                           HttpServletResponse response) {
        
        log.info("请求播放视频文件: fileId={}, range={}", fileId, range);
        
        try {
            // 根据文件ID获取文件信息
            Long id = Long.parseLong(fileId);
            FileIndex fileIndex = fileIndexService.getById(id);
            if (fileIndex == null) {
                log.warn("文件不存在: fileId={}", fileId);
                response.sendError(HttpServletResponse.SC_NOT_FOUND, "文件不存在");
                return;
            }
            
            log.info("找到文件: {}", fileIndex.getFilePath());
            
            Path filePath = Paths.get(fileIndex.getFilePath());
            if (!Files.exists(filePath)) {
                log.warn("物理文件不存在: {}", filePath);
                response.sendError(HttpServletResponse.SC_NOT_FOUND, "物理文件不存在");
                return;
            }
            
            File file = filePath.toFile();
            long fileSize = file.length();
            String fileName = fileIndex.getFileName();
            String fileType = fileIndex.getFileType();
            
            log.info("准备传输文件: name={}, size={}, type={}", fileName, fileSize, fileType);
            
            // 设置基础响应头
            response.setContentType(getMediaType(fileType).toString());
            response.setHeader("Accept-Ranges", "bytes");
            response.setHeader("Content-Disposition", "inline; filename=\"" + fileName + "\"");
            
            // 处理 Range 请求（支持断点续传和流媒体播放）
            if (range != null && range.startsWith("bytes=")) {
                handleRangeRequest(file, range, response);
            } else {
                // 完整文件传输
                response.setContentLengthLong(fileSize);
                response.setStatus(HttpServletResponse.SC_OK);
                
                try (FileInputStream fis = new FileInputStream(file);
                     BufferedInputStream bis = new BufferedInputStream(fis);
                     OutputStream os = response.getOutputStream()) {
                    
                    byte[] buffer = new byte[8192];
                    int bytesRead;
                    while ((bytesRead = bis.read(buffer)) != -1) {
                        os.write(buffer, 0, bytesRead);
                    }
                    os.flush();
                }
            }
                    
        } catch (ClientAbortException e) {
            log.debug("客户端中断视频流连接: fileId={}", fileId);
        } catch (IOException e) {
            if (e.getMessage() != null && e.getMessage().contains("Connection reset")) {
                log.debug("客户端重置连接: fileId={}", fileId);
            } else {
                log.error("流式传输IO异常: fileId={}", fileId, e);
                try {
                    if (!response.isCommitted()) {
                        response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "传输失败");
                    }
                } catch (IOException ignored) {
                }
            }
        } catch (Exception e) {
            log.error("流式传输文件失败: fileId={}", fileId, e);
            try {
                if (!response.isCommitted()) {
                    response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "服务器错误");
                }
            } catch (IOException ignored) {
            }
        }
    }
    
    /**
     * 处理 Range 请求
     */
    private void handleRangeRequest(File file, String range, HttpServletResponse response) throws IOException {
        long fileSize = file.length();
        
        // 解析 Range 头
        String[] ranges = range.substring(6).split("-");
        long start = 0;
        long end = fileSize - 1;
        
        if (ranges.length > 0 && !ranges[0].isEmpty()) {
            start = Long.parseLong(ranges[0]);
        }
        if (ranges.length > 1 && !ranges[1].isEmpty()) {
            end = Long.parseLong(ranges[1]);
        }
        
        // 确保范围有效
        if (start >= fileSize || end >= fileSize || start > end) {
            response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
            response.setHeader("Content-Range", "bytes */" + fileSize);
            return;
        }
        
        long contentLength = end - start + 1;
        
        // 设置 206 部分内容响应
        response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileSize);
        response.setContentLengthLong(contentLength);
        
        log.debug("Range请求: {}-{}/{}, length={}", start, end, fileSize, contentLength);
        
        // 传输指定范围的内容
        try (RandomAccessFile raf = new RandomAccessFile(file, "r");
             OutputStream os = response.getOutputStream()) {
            
            raf.seek(start);
            byte[] buffer = new byte[8192];
            long remaining = contentLength;
            
            while (remaining > 0) {
                int toRead = (int) Math.min(buffer.length, remaining);
                int bytesRead = raf.read(buffer, 0, toRead);
                if (bytesRead == -1) break;
                
                os.write(buffer, 0, bytesRead);
                remaining -= bytesRead;
            }
            os.flush();
        }
    }
    
    /**
     * 根据文件类型获取 MediaType
     */
    private MediaType getMediaType(String fileType) {
        return switch (fileType.toLowerCase()) {
            case "mp4", "m4v" -> MediaType.parseMediaType("video/mp4");
            case "avi" -> MediaType.parseMediaType("video/x-msvideo");
            case "mkv" -> MediaType.parseMediaType("video/x-matroska");
            case "mov" -> MediaType.parseMediaType("video/quicktime");
            case "wmv" -> MediaType.parseMediaType("video/x-ms-wmv");
            case "flv" -> MediaType.parseMediaType("video/x-flv");
            case "webm" -> MediaType.parseMediaType("video/webm");
            case "mpg", "mpeg" -> MediaType.parseMediaType("video/mpeg");
            case "3gp" -> MediaType.parseMediaType("video/3gpp");
            case "asf" -> MediaType.parseMediaType("video/x-ms-asf");
            case "rm", "rmvb" -> MediaType.parseMediaType("application/vnd.rn-realmedia");
            default -> MediaType.parseMediaType("video/mp4");
        };
    }
}